﻿#include"stdafx.h"
#ifdef LK_REFLECTION_
namespace LK
{
	namespace Reflection
	{
		bool PFunctionNode::AddFunction(Functional::PFunObjs fun)const { return AddFunction(fun, Convert<PDomainNode, ptr<Object>>::RefFrom(ptr<Object>())); }
		bool PFunctionNode::AddFunction(Functional::PFunObjs fun, PDomainNode domain)const
		{
			return Check()->AddFunction(fun, domain);
		}
		bool PFunctionNode::AddOperatorFunction(Functional::PFunObjs fun)const
		{
			return Check()->AddOperatorFunction(fun);
		}
		/**
		@brief 动态传参并调用方法
		@note 该方法在找不到合适的重载时会抛出FunctionOverloadNotFoundException*/
		ptr<Object> PFunctionNode::DynamicCall(ptr<Object> const& obj, ptr<Collection::IArray<ptr<Object>>>args)const
		{
			ptr<Collection::IArray<ptr<Type>>>targs(args==null?0:args->size());
			for (index_t i = 0; i < (args==null ? 0 : args->size()); ++i)
			{
				targs[i] = args[i]->GetType();
				if (targs[i] == Type::Make<PMObjects>())
					targs[i] = ((PMObjects&)args[i])->GetInnerType();
			}
			Functional::PFunObjs f = GetFunction(targs);
			if(f==null)
				Throw<PFunctionOverloadNotFoundException >();
			return f->Call(obj, args);
		}
		/**
		@brief 动态传入参数类型以获取调用的重载版本
		@param [传入，可省]参数isExplicit用以指示是否精确匹配，默认为false
		@note 该方法在找不到合适的重载时会返回NULL*/
		Functional::PFunObjs PFunctionNode::GetFunction(ptr<Collection::IArray<ptr<Type>>>args, bool isExplicit)const
		{
			return Check()->GetFunction(args,isExplicit);
		}

		/**
		@brief 动态传入参数类型以获取调用的重载版本
		@param [传入，可省]参数isExplicit用以指示是否精确匹配，默认为false
		@note 该方法在找不到合适的重载时返回NULL*/
		Functional::PFunObjs FunctionNode::GetFunction(ptr<Collection::IArray<ptr<Type>>>t,bool isExplicit)const
		{
			index_t i = Methods->DichotomyIndexOf(t, &FunctionNode::ConstructCompare);
			if (i >= 0)
			{
				if (t==null || t->size() == 0)return Methods[i];
				ptr<Collection::IArray<ptr<Type>>> tarr;
				bool bf = false;
			ReFind:;
				tarr = Methods[i]->GetArgsType();
				index_t cmp = (tarr->size() < (t==null ? 0 : t->size()) + 2) ? -1 : (tarr->size() > (t==null ? 0 : t->size())  + 2) ? 1 : 0;
				index_t rcmp = cmp;
				if (cmp == 0)for (index_t k = 0; k < (t==null ? 0 : t->size()); ++k)
				{
					rcmp = tarr[k + 2]->CompareWithoutExtents(t[k]);
					if (cmp == 0)cmp = tarr[k + 2]->CompareWith(t[k]);
					if (rcmp != 0) { cmp = rcmp; break; }
				}
				if (i > 0 && cmp>0) { i--; bf = true; if (rcmp == 0)goto ReFind; }
				else if (i < Methods->size() && cmp<0) { i++; if (!bf&&rcmp == 0)goto ReFind; }
				return Methods[i];
			}
			//找不到将进行模糊查询
			for (i = 0; i < Methods->size(); ++i)
			{
				ptr<Collection::IArray<ptr<Type>>> tarr = Methods[i]->GetArgsType();
				index_t cmp = (tarr->size() < t->size() + 2) ? -1 : (tarr->size() > t->size() + 2) ? 1 : 0;
				if (cmp == 0)
				{
					index_t k;
					for (k = 0; k < t->size(); ++k)
						if (!tarr[k + 2]->CanDynamicConvertFrom(t[k],isExplicit?0:1))break;
					if (k == t->size())return Methods[i];
				}
			}
			return Functional::PFunObjs();
		}

		FunctionNode::FunctionNode(ptr<String> const& name, weakptr<TypeLibrary> const&  library, PDomainNode const& baseNode)
			:LibraryNode(library, baseNode, name),InDomain(false) {}
		bool FunctionNode::AddFunction(Functional::PFunObjs fun){return AddFunction(fun,Convert<PDomainNode,ptr<Object>>::RefFrom(ptr<Object>()));}
		bool FunctionNode::AddFunction(Functional::PFunObjs fun, PDomainNode domain)
		{
			if (fun==null)Throw<PInvalidArgumentException>(L"传入的函数为空");
			if (GetBaseNode()!=null) {
				if (domain!=null && InDomain&& !domain ->Equals( GetBaseNode()))return false;
				if (!InDomain && (domain==null || domain ->Equals( GetBaseNode()))) {
					InDomain = true;
					Methods=null;
				}
			}
			if (Methods==null)
                Methods = new LK::Collection::DefaultArray<Functional::PFunObjs>();
			for (index_t i = 0; i < Methods->size(); ++i)
				if (Methods[i]->Equals(fun))return false;
			Methods->DichotomyInsertAsc(fun,&FunctionNode::FunctionCompare);
			return true;
		}
		bool FunctionNode::AddOperatorFunction(Functional::PFunObjs fun)
		{
			if (fun==null)Throw<PInvalidArgumentException>(L"传入的函数为空");
			if (Methods==null)Methods = new LK::Collection::DefaultArray<Functional::PFunObjs>();
			for (index_t i = 0; i < Methods->size(); ++i)
				if (Methods[i]->Equals(fun))return false;
			Methods->DichotomyInsertAsc(fun, &FunctionNode::OperatorFunctionCompare);
			return true;
		}
		index_t FunctionNode::FunctionCompare(Functional::PFunObjs const&f1, Functional::PFunObjs const&f2)
		{
			ptr<Collection::IArray<ptr<Type>>> arr2 = f2->GetArgsType();
			return FunctionTypeCompare(f1,arr2);
		}
		index_t FunctionNode::FunctionTypeCompare(Functional::PFunObjs const&f1, ptr<Collection::IArray<ptr<Type>>> const&arr2)
		{
			ptr<Collection::IArray<ptr<Type>>> arr1 = f1->GetArgsType();
			if (arr1->size() != arr2->size())return arr1->size()>arr2->size() ? 1 : -1;
			if (arr1->size() == 2)return 0;
			for (index_t i = 2; i < arr1->size(); ++i)
			{
				index_t cmp = arr1[i]->CompareWithoutExtents(arr2[i]);
				if (cmp != 0)return cmp;
			}
			for (index_t i = 2; i < arr1->size(); ++i)
				if (arr1[i].GetPtr()->GetAttribute() != arr2[i].GetPtr()->GetAttribute())return arr1[i].GetPtr()->GetAttribute() - arr2[i].GetPtr()->GetAttribute();
			return 0;
		}
		index_t FunctionNode::OperatorFunctionCompare(Functional::PFunObjs const&f1, Functional::PFunObjs const&f2)
		{
			ptr<Collection::IArray<ptr<Type>>> arr1 = f1->GetArgsType();
			ptr<Collection::IArray<ptr<Type>>> arr2 = f2->GetArgsType();
			if (arr1->size() != arr2->size())return arr1->size()>arr2->size() ? 1 : -1;
			index_t cmp = arr1[0]->CompareWithoutExtents(arr2[0]);
			if (cmp != 0)return cmp;
			if (arr1[0].GetPtr()->GetAttribute() != arr2[0].GetPtr()->GetAttribute())return arr1[0].GetPtr()->GetAttribute() - arr2[0].GetPtr()->GetAttribute();
			return 0;
		}
		index_t FunctionNode::ConstructCompare(Functional::PFunObjs const&f1, ptr<Collection::IArray<ptr<Type>>> const&arr2)
		{
			ptr<Collection::IArray<ptr<Type>>> arr1= f1->GetArgsType();
			if (arr1->size() != (arr2==null?2:arr2->size()+2))return arr1->size()>(arr2==null ? 2 : arr2->size() + 2) ? 1 : -1;
			if (arr1->size() == 2)return 0;
			for (index_t i = 0; i < arr1->size(); ++i)
			{
				if (arr1->size() == 2 && arr2==null)break;
				index_t cmp = arr1[i + 2]->CompareWithoutExtents(arr2[i]);
				if (cmp!=0)return cmp;
			}
			return 0;
		}
		index_t FunctionNode::OperatorCompare(Functional::PFunObjs const&t1, ptr<Type> const&t2)
		{
			return t1->GetArgsType()[0]->CompareWithoutExtents(t2);
		}
	}
}
#endif
